package com;

public class 多线程单例的DCL {
    /**
     * 这里我们为甚要加volatile呢，因为在我们的java代码中可能乱序执行
     * L9
     *     LINENUMBER 23 L9
     *     NEW com/baidu/aaa/多线程单例的DCL
     *     DUP
     *     INVOKESPECIAL com/baidu/aaa/多线程单例的DCL.<init> ()V
     *     PUTSTATIC com/baidu/aaa/多线程单例的DCL.INSTANCE : Lcom/baidu/aaa/多线程单例的DCL;
     * 如果在我们的第一个线程执行了先执行了NEW(开辟空间)的操作，让后后面的创建对象<init>方法和创建对象应用的方法进行了指令重排，
     * 那么就相当于这个对象还没有new出来，但是已经先给他分配了值，这个时候第二个对象来了之后直接判断里面有值，那么的话就会让我们
     * 的第二个对象获取到我们这个创建到一般，还没有初始化(没有执行构造方法)的半成品对象，这个时候直接使用我们的对象就会出现问题，
     * 所以为了防止这种情况发生，我们要田间volatile关键字来防止我们的指令重排(构造方法比较复杂可能遇到)
     */
    private volatile static 多线程单例的DCL INSTANCE;

    public static 多线程单例的DCL get多线程单例的DCL() throws InterruptedException {
        // 在这里我们使用DCL(Double Check Lock来保证我们的变量)
        // 第一个if是为了防止我们的所有的代码都加锁导致效率低下
        if(INSTANCE==null){
            synchronized (多线程单例的DCL.class){
                // 第二个if是为了保证我们的代码原子性，因为进来第一个if判断的可能不止一个线程
                if (INSTANCE==null){
                    Thread.sleep(100);
                    INSTANCE = new 多线程单例的DCL();
                }
            }
        }
        return INSTANCE;
    }

    public static void main(String[] args) throws InterruptedException {
        for (int i = 0; i < 100; i++) {
            new Thread(()->{
                try {
                    System.out.println(多线程单例的DCL.get多线程单例的DCL().hashCode());
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }).start();
        }
        Thread.sleep(10000);
    }
}
